import html2canvas, { Options } from 'html2canvas';
import jsPDF from 'jspdf';

/**
 * 下载 PDF 文件，将指定的 DOM 元素转换为 PDF 格式并下载
 * @param {HTMLElement} dom 元素实例
 * @param {string} fileName 文件名
 * @param {Partial<Options>} options html2canvas 的配置项
 */
export async function downloadPdf(dom: HTMLElement | null, fileName: string = 'download', options: Partial<Options> = {}) {
	// 若传入的 DOM 元素为空，则直接返回
	if (!dom) return;

	const { backgroundColor = 'white', scale = 4 } = options;

	// 利用 html2canvas 将 HTML 元素渲染为 canvas 对象
	const canvas = await html2canvas(dom, {
		backgroundColor,
		scale, // 提高清晰度
		useCORS: true,
		allowTaint: true,
		logging: false
	});

	// 创建一个新的 jsPDF 实例，设置为纵向 A4 纸大小
	const pdf = new jsPDF('p', 'mm', 'a4');

	// 获取 canvas 的 2D 绘图环境
	const ctx = canvas.getContext('2d');

	// A4 纸的宽度和高度（单位：毫米），预留边距
	const a4w = 190;
	const a4h = 280;

	// 根据 A4 纸的高度和 canvas 的宽度，计算每页图像应有的像素高度
	const imgHeight = Math.floor((a4h * canvas.width) / a4w);

	// 已渲染内容的高度
	let renderedHeight = 0;

	// 循环处理 canvas 内容，分页渲染到 PDF
	while (renderedHeight < canvas.height) {
		// 创建一个新的 canvas 对象，用于处理单页内容
		const page = document.createElement('canvas');
		page.width = canvas.width;
		page.height = Math.min(imgHeight, canvas.height - renderedHeight);

		// 从原 canvas 中剪裁出当前页的内容
		const imageData = ctx?.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight));
		if (!imageData) break;
		page.getContext('2d')?.putImageData(imageData, 0, 0);

		// 将当前页添加到 PDF 中
		pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 5, a4w, Math.min(a4h, (a4w * page.height) / page.width));

		// 更新已渲染内容的高度
		renderedHeight += imgHeight;

		// 如果还有剩余内容，添加新页面
		if (renderedHeight < canvas.height) {
			pdf.addPage();
		}
	}

	// 保存并命名生成的 PDF 文档
	pdf.save(`${fileName}.pdf`);
}
